package com.zjhcsoft.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.zjhcsoft.auth.common.enums.PasswordType;
import com.zjhcsoft.auth.common.enums.StatusCode;
import com.zjhcsoft.auth.common.enums.UserCredentialType;
import com.zjhcsoft.auth.common.utils.RandomUtils;
import com.zjhcsoft.auth.common.vo.Result;
import com.zjhcsoft.auth.entity.Account;
import com.zjhcsoft.auth.entity.AppResource;
import com.zjhcsoft.auth.entity.Corporation;
import com.zjhcsoft.auth.entity.Password;
import com.zjhcsoft.auth.entity.User;
import com.zjhcsoft.auth.entity.UserCredential;
import com.zjhcsoft.auth.entity.UserDevice;
import com.zjhcsoft.auth.entity.web.QueryCheckTypesRequest;
import com.zjhcsoft.auth.entity.web.QueryCorporationRequest;
import com.zjhcsoft.auth.entity.web.QueryCredentialRequest;
import com.zjhcsoft.auth.entity.web.QueryDeviceRequest;
import com.zjhcsoft.auth.entity.web.QueryUserInfoRequest;
import com.zjhcsoft.auth.entity.web.UpdateCheckTypeRequest;
import com.zjhcsoft.auth.entity.web.UpdateCredentialRequest;
import com.zjhcsoft.auth.entity.web.UpdateDeviceRequest;
import com.zjhcsoft.auth.entity.web.UpdateMobileRequest;
import com.zjhcsoft.auth.entity.web.UpdatePasswordRequest;
import com.zjhcsoft.auth.service.AccountService;
import com.zjhcsoft.auth.service.AppResourceService;
import com.zjhcsoft.auth.service.CorporationService;
import com.zjhcsoft.auth.service.PasswordService;
import com.zjhcsoft.auth.service.SmsService;
import com.zjhcsoft.auth.service.UserCredentialService;
import com.zjhcsoft.auth.service.UserDeviceService;
import com.zjhcsoft.auth.service.UserService;
import com.zjhcsoft.crm.auth.entity.*;
import com.zjhcsoft.auth.dao.AccountMapper;
import com.zjhcsoft.crm.auth.entity.web.*;
import com.zjhcsoft.crm.auth.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 账号表 服务实现类
 * </p>
 *
 * @author wzya
 * @since 2021-03-29
 */
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements
    AccountService {

    @Autowired
    UserCredentialService credentialService;
    @Autowired
    SmsService smsService;
    @Autowired
    AppResourceService appService;
    @Autowired
    UserDeviceService deviceService;
    @Autowired
    PasswordService passwordService;
    @Autowired
    UserService userService;
    @Autowired
    CorporationService corporationService;

    @Override
    public Account getAccountByChannelAndCorporationAndCredential(String channelCode, String corporationCode, String credential) {
        AppResource app = appService.getAppResourceByChannelCodeAndCorporationCode(channelCode,corporationCode);
        List<Long> accountIds = credentialService.lambdaQuery().eq(UserCredential::getCredential,credential).eq(UserCredential::getCredentialStatus, StatusCode.ON.getCode()).list().stream().map(userCredential ->userCredential.getAccountId()).collect(Collectors.toList());
        Account account = this.lambdaQuery().in(Account::getId,accountIds).eq(Account::getAppId,app.getId()).one();
        return account;
    }

    @Override
    public Account getAccountByChannelAndCorporationAndClientNo(String channelCode, String corporationCode, String clientNo) {
        User user = userService.lambdaQuery().eq(User::getClientNo,clientNo).one();
        AppResource app = appService.getAppResourceByChannelCodeAndCorporationCode(channelCode,corporationCode);
        Account account = this.lambdaQuery().eq(Account::getSysUserId,user.getId()).eq(Account::getAppId,app.getId()).one();
        return account;
    }

    @Override
    public Result updateMobile(UpdateMobileRequest request) {

        if(smsService.smsVrfcCodeValidate(request.getUntyMobile(),request.getMessageCode())){
            Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getAcctNo());
            Boolean res = false;

            try{
                res = credentialService.lambdaUpdate()
                        .eq(UserCredential::getCredentialType, UserCredentialType.MOBILE.getCode())
                        .eq(UserCredential::getAccountId,account.getId())
                        .set(UserCredential::getCredential,request.getBindMobile()).update();
            }catch (Exception e){
                return Result.error("update mobile error. "+e.getMessage());
            }
            return Result.ok(res);
        }else {
            return Result.error(" incorrect sms verification code.");
        }
    }

    @Override
    public Result updateDevice(UpdateDeviceRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        if(null!=account){
            if("0".equals(request.getOperatorType())){
                //TODO..设备绑定策略校验
                deviceService.save(new UserDevice(){{
                    setAccountId(account.getId());
                    setSeId(request.getSeId());
                }});
                return Result.ok();

            }else if("1".equals(request.getOperatorType())){
                UserDevice device = deviceService.lambdaQuery().eq(UserDevice::getAccountId,account.getId()).eq(UserDevice::getSeId,request.getSeId()).one();
                if(null!=device){
                    return Result.ok(deviceService.removeById(device.getId()));
                }else {
                    return Result.error("not found se_id"+request.getSeId()+" from "+request.getUserCredential());
                }
            }else {
                return Result.error("error operator type.");
            }
        }
        return Result.error("error credential info.");
    }

    @Override
    public Result updatePassword(UpdatePasswordRequest request) {
        if(!smsService.smsVrfcCodeValidate(request.getMobile(),request.getSmsVrfcCd())){
            return Result.error("incorrect sms vrfc code.");
        }

        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        //密码复杂度校验
        if(!passwordService.passwordComplexityValidate(request.getNewPassword())){
            return Result.error("password complexity validate failed.");
        }
        //原密码
        Password oldPassword = passwordService.lambdaQuery()
                .eq(Password::getAccountId,account.getId())
                .eq(Password::getCheckType, PasswordType.STATIC.getCode()).one();

        //设置密码
        if("0".equals(request.getOperatorType())){
            if(null!=oldPassword){
                oldPassword.setPassward(request.getNewPassword());//TODO..加密
                return Result.ok(passwordService.updateById(oldPassword));
            }else {
                passwordService.save(new Password(){{
                    setPassward(request.getNewPassword());//TODO..加密
                    setAccountId(account.getId());
                    setCheckType( PasswordType.STATIC.getCode());
                    setPasswordStatus(StatusCode.ON.getCode());
                }});
                return Result.ok("password update success.");
            }
        }
        //修改密码
        if("1".equals(request.getOperatorType())){
            if(passwordService.passwordValidate(request.getOldPassword(),oldPassword.getPassward())){
                oldPassword.setPassward(request.getNewPassword());//TODO..加密
                passwordService.updateById(oldPassword);
                return Result.ok("password update success.");
            }else {
                Result.error("incorrect old password.");
            }
        }

        //忘记密码
        if("2".equals(request.getOperatorType())){
            if(smsService.smsVrfcCodeValidate(request.getMobile(),request.getSmsVrfcCd())){
                oldPassword.setPassward(request.getNewPassword());//TODO..加密
                passwordService.updateById(oldPassword);
                return Result.ok("password update success.");
            }else {
                return Result.error("incorrect sms verification code.");
            }
        }
        return Result.error(" operator type is null;");
    }

    @Override
    public Result queryDevice(QueryDeviceRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        List<UserDevice> devices = deviceService.lambdaQuery().eq(UserDevice::getAccountId,account.getId()).list();
        return Result.ok(devices);
    }

    @Override
    public Result queryCheckType(QueryCheckTypesRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        List<Password> list = passwordService.lambdaQuery().eq(Password::getAccountId,account.getId()).select(Password::getCheckType,Password::getPasswordStatus).list();
        return Result.ok(list);
    }

    public Result updateCheckType(UpdateCheckTypeRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        //static不可变更，默认开启
        if(PasswordType.STATIC.getCode().equals(request.getCheckType())) return Result.error("static password Cannot be closed.");

        Password password = passwordService.lambdaQuery().eq(Password::getAccountId,account.getId()).eq(Password::getCheckType,request.getCheckType()).one();
        //操作类型，0-开 1-关
        if("0".equals(request.getOperatorType())){
            //已存在
            if(null!=password){
                //重复开通
                if(StatusCode.ON.getCode().equals(password.getPasswordStatus())){
                    return Result.error(" this check type already has been opened.");
                }else {
                    if(PasswordType.GESTURE.getCode().equals(request.getCheckType())){
                        password.setPassward(request.getPassword());
                    }
                    password.setPasswordStatus(StatusCode.ON.getCode());
                    passwordService.updateById(password);
                    return updateCheckTypeResponse(password);
                }
            }else {
                Password newPassword = new Password();
                newPassword.setAccountId(account.getId());
                newPassword.setCheckType(request.getCheckType());
                newPassword.setPasswordStatus(StatusCode.ON.getCode());
                if(PasswordType.GESTURE.getCode().equals(request.getCheckType())){
                    newPassword.setPassward(request.getPassword());
                }else {
                    newPassword.setPassward(RandomUtils.randomStr(32));
                }
                passwordService.save(newPassword);
                return updateCheckTypeResponse(newPassword);
            }
        }else if("1".equals(request.getOperatorType())){
            if(null!=password){
                //重复关闭
                if(StatusCode.OFF.getCode().equals(password.getPasswordStatus())){
                    return Result.error(" this check type already has been closed.");
                }else {
                    password.setPasswordStatus(StatusCode.OFF.getCode());
                    return updateCheckTypeResponse(password);
                }
            }else {
                return Result.error(" this check type not open.");
            }
        }else {
            return Result.error(" wrong operation type.");
        }

    }
    /**组装校验方式返回***/
    private Result updateCheckTypeResponse(Password password){
        if(PasswordType.CLIENT_FACE.getCode().equals(password.getCheckType()) ||
                PasswordType.CLIENT_FINGER.getCode().equals(password.getCheckType())){
            return Result.ok(password.getPassward());
        }else {
            return Result.ok("operation success.");
        }
    }

    @Override
    public Result queryCredential(QueryCredentialRequest request) {
        if(null!=request.getClientNo()){
            User user = userService.lambdaQuery().eq(User::getClientNo,request.getClientNo()).one();
            AppResource app = appService.getAppResourceByChannelCodeAndCorporationCode(request.getChannelCode(),request.getCorporationCode());
            Account account = this.lambdaQuery().eq(Account::getSysUserId,user.getId()).eq(Account::getAppId,app.getId()).one();
            List<String> credentials = credentialService.lambdaQuery().eq(UserCredential::getAccountId,account.getId()).eq(UserCredential::getCredentialStatus,StatusCode.ON.getCode()).list().stream().map(credential -> credential.getCredential()).collect(Collectors.toList());
            return Result.ok(credentials);
        }else {
            return Result.error("clientNo is null.");
        }
    }

    @Override
    @Transactional
    public Result updateCredential(UpdateCredentialRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndClientNo(request.getChannelCode(),request.getCorporationCode(),request.getClientNo());
        Map<Boolean,List<Result>> res =request.getOperations().stream().map(operation->{
            UserCredential credential = credentialService.lambdaQuery().eq(UserCredential::getAccountId,account.getId()).eq(UserCredential::getCredential,operation.getUserCredential()).one();
            if(null!=credential){
                credential.setCredentialStatus(operation.getIsOpen());
                if(credentialService.updateById(credential)){
                    return Result.ok();
                }else {
                    return Result.error(operation.getUserCredential()+" operation failed.");
                }
            }else {
                return Result.error(operation.getUserCredential()+" operation failed. credential not found.");
            }
        }).collect(Collectors.toList()).stream().collect(Collectors.groupingBy(Result::isSuccess));
        if(res.containsKey(false)){
            return Result.error(JSON.toJSONString(res.get(false)));
        }else {
            return Result.ok();
        }
    }

    @Override
    public Result queryUserInfo(QueryUserInfoRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        User user = userService.getById(account.getSysUserId());
        if(null!=user){
            user.setRegisterTime(user.getCreatedTime());
            return Result.ok(user);
        }else {
            return Result.error("invalid credential.");
        }
    }

    @Override
    public Result queryCorporation(QueryCorporationRequest request) {
        Account account = this.getAccountByChannelAndCorporationAndCredential(request.getChannelCode(),request.getCorporationCode(),request.getUserCredential());
        List<Long> appIds = this.lambdaQuery().eq(Account::getSysUserId,account.getSysUserId()).select(Account::getAppId).list().stream().map(account1 -> account1.getAppId()).distinct().collect(Collectors.toList());
        List<Long> corporationIds = appService.lambdaQuery().in(AppResource::getId,appIds).list().stream().map(appResource -> appResource.getCorporationId()).distinct().collect(Collectors.toList());
        List<Corporation> corporations = corporationService.lambdaQuery().in(Corporation::getId,corporationIds).list();
        return Result.ok(corporations);
    }


}
